#pragma once
#ifndef OBR_SHADER_SAMPLING_CUH
#define OBR_SHADER_SAMPLING_CUH

#include "../common.cuh"
#include "MathDataUtils.cuh"

namespace OBR
{
static __forceinline__ __device__ float3 cosine_sample_hemisphere(float u0, float u1)
{
    // Uniformly sample disk.
    const float r = sqrtf(u0);
    const float phi = 2.0f * M_PIf * u1;
    // Project up to hemisphere.
    float3 p;
    p.x = r * cosf(phi);
    p.y = r * sinf(phi);
    p.z = sqrtf(fmaxf(0.0f, 1.0f - p.x * p.x - p.y * p.y));
    return p;
}

static __forceinline__ __device__ float lightAreaPDFToSolidAnglePDF(RayData wo, float3 n, float r,
                                                                    float areaPDF)
{
    return areaPDF * fabsf(dot(wo.d, n)) / (r * r);
}

// Computes a point using the Fibonacci sequence of length N.
// Input: Fib[N - 1], Fib[N - 2], and the index 'i' of the point.
// Ref: Efficient Quadrature Rules for Illumination Integrals
static __forceinline__ __device__ float2 Fibonacci2dSeq(float fibN1, float fibN2, uint i)
{
    // 3 cycles on GCN if 'fibN1' and 'fibN2' are known at compile time.
    // N.b.: According to Swinbank and Pusser [SP06], the uniformity of the distribution
    // can be slightly improved by introducing an offset of 1/N to the Z (or R) coordinates.
    return make_float2(i / fibN1 + (0.5 / fibN1), fracf(i * (fibN2 / fibN1)));
}

// Sample count must be a Fibonacci number (see 'k_FibonacciSeq').
static __forceinline__ __device__ float2 Fibonacci2d(uint i, uint sampleCount)
{
    uint fibN1 = sampleCount;
    uint fibN2 = sampleCount;
    static const uint k_FibonacciSeq[] = {0,  1,  1,   2,   3,   5,   8,   13,   21,   34,
                                          55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181};
    // These are all constants, so this loop will be optimized away.
    for (uint j = 1; j < 20; j++)
    {
        if (k_FibonacciSeq[j] == fibN1)
        {
            fibN2 = k_FibonacciSeq[j - 1];
        }
    }

    return Fibonacci2dSeq(fibN1, fibN2, i);
}

} // namespace OBR

#endif
